/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pkwserver;

//import blindsignature.ClientVoteManager;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.logging.Level;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import javax.security.cert.CertificateException;

/* Do ściągnięcia z
 * http://www.jdom.org/dist/binary/jdom-1.1.2.zip
 */
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.jdom.*;
import org.jdom.output.*;
import pl.pkw.client.ClientTool;
import pl.pkw.common.Card;
import pl.pkw.common.Tool;
import pl.pkw.common.Vote;
import pl.pkw.common.VotingData;
import pl.pkw.server.ServerTool;

/**
 *
 * @author Pawel
 */
public class PKWClient {
    private static SSLSocketFactory getFactory(File pKeyFile, String pKeyPassword) throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, KeyManagementException, java.security.cert.CertificateException{
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509");
            KeyStore trustStore = KeyStore.getInstance("JKS");
            SSLContext ctx;
            ctx = SSLContext.getInstance("TLS");
            
            trustStore.load(new FileInputStream(pKeyFile), pKeyPassword.toCharArray());
            trustManagerFactory.init(trustStore);
            ctx.init(null,trustManagerFactory.getTrustManagers(), new SecureRandom());
            return ctx.getSocketFactory();
    }
    
    public static void main(String[] args) {
        try {
            // SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
            SSLSocketFactory sslsocketfactory = (SSLSocketFactory) getFactory(new File("clientkeystore.jks"), "bskbsk");
            SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("localhost", 9999);
            sslsocket.setUseClientMode(true);
            InputStream inputstream = sslsocket.getInputStream();
            InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
            BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

            OutputStream outputstream = sslsocket.getOutputStream();
            OutputStreamWriter outputstreamwriter = new OutputStreamWriter(outputstream);
            BufferedWriter bufferedwriter = new BufferedWriter(outputstreamwriter, 16783);

            String string = null;
            
            System.out.println("Starting SSL client");
            //System.out.println(sslsocket.getPort());
            sslsocket.startHandshake();
//            ClientVoteManager cvm = new ClientVoteManager();
//            cvm.manage();
            // Hello message
            Element msg = new Element("msg");
            Document doc = new Document(msg);
            Element content = new Element("content");
            content.addContent("HELLO nnnnnnn ooooooooooooooooooooooooooooooooooooo");
            msg.addContent(content);
//-------------------------------------------------------------------------            
            //server side
            ServerTool st = new ServerTool();
            //sent to client e, n, lista kandydatow  (template card)        
            
            Vote vote = new Vote(2);
            vote.setVoteCard(new BigInteger("123A".getBytes("UTF-8")));
            vote.calculateHashVote();
            
            BigInteger r,e,n,d;
            e = st.getE();
            n = st.getN();
            d = st.getD();
            r = Tool.r(n);
            
            vote.setBlindVote(Tool.blind(vote.getHashVote(), e, n, r));
            vote.setBlindSignVote(Tool.sign(vote.getBlindVote(), d, n));
            vote.setSignUnblindVote(Tool.unblind(vote.getBlindSignVote(), n, r));
            Tool.verify(vote.getSignUnblindVote(), vote.getHashVote(), d, n);
            Tool.verifyByRSA(vote.getSignUnblindVote(), vote.getHashVote(), e, n);
            
            System.out.println("unb b");
            vote.setSignUnblindVote(Tool.unblindToClean(vote.getBlindVote(), e, n, r));
            String aa = new String(vote.getSignUnblindVote().toByteArray());
            Tool.verifyByRSA(vote.getSignUnblindVote(), vote.getHashVote(), e, n);
            
            
            //client side
            ClientTool ct = new ClientTool(st.getE(), st.getN());            
            ct.blind();
            send(bufferedwriter, ct.getVotingData());            
            
            //server side
            st.setClientVotingData(ct.getVotingData());
            Integer number = st.randomCard();
            //sent to client number
            
            
            //client side
            ct.blindN1(number);
            //send(bufferedwriter, ct.getVotingData());
            
            //server side
            //dane z r
            Boolean valid = st.verifyBlind(ct.getVotingData());            
            if(!valid){ throw new Exception("Cards are invalid!");}
            
            //podpisujemy karte
            Card signCard = st.signCard();
            
            //sent to client
            
            //client side
            ct.getVotingData().setSkipCard(signCard);            
            ct.unblindSignCard();
            Vote signVote = ct.vote();
            System.out.println("select sign vote \n " + signVote.getHashVote());
            
            st.verifyVote(signVote);
            
            
            
            
            
            
            
            //bufferedwriter.write(out.toString());
            bufferedwriter.flush();
            
            //string = bufferedreader.readLine();
            BufferedInputStream bis = new BufferedInputStream(sslsocket.getInputStream());
            byte[] recvData = new byte[8192];
            bis.read(recvData);
            string = new String(recvData);
            System.out.println("client socket ins: " + string);
            
            /*
            while ((string = bufferedreader.readLine()) != null) {
                bufferedwriter.write("client" + string + '\n');
                bufferedwriter.flush();
            }*/
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        
        
    }
    
    
    private static void send(BufferedWriter bufferedwriter, VotingData votingData) throws JAXBException, XMLStreamException, IOException
    {
    
            JAXBContext context;       
            context = JAXBContext.newInstance(VotingData.class);
            

            //XMLOutputter out = new XMLOutputter();
            XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(bufferedwriter);
            
            Marshaller m = context.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
            m.setProperty("jaxb.encoding", "Unicode");
            
            m.marshal(votingData, xmlStreamWriter);
            //bufferedwriter.flush();
    }
}
